import os
import csv
import random
import json
import random
import sys
import numpy as np
from geopy.distance import geodesic
from gps2grid import SpatialRegion

def zip_sensing_locs(obj_loc):
    with open('./ngram_statistics/radius_100/trigram/KMM3_4000k.json') as bf:
        prob_matrix = json.load(bf)

    prob_locs = prob_matrix[obj_loc]
    sensing_locs = sorted(prob_locs.items(), key = lambda item:item[1], reverse=True)[1:6]
    total = 0
    for i in range(len(sensing_locs)):
        total += sensing_locs[i][1]
    for i in range(len(sensing_locs)):
        sensing_locs[i] = list(sensing_locs[i])
        sensing_locs[i][1] = sensing_locs[i][1]/total

    return sensing_locs

def number_of_certain_prob(seq, prob):
    x = random.uniform(0,1)
    cumulative_prob = 0.0
    for item, item_prob in zip(seq, prob):
        cumulative_prob += item_prob
        if x < cumulative_prob:
            break
    return item

def workers_assign2loc(sensing_locs, worker_num):
    rate = list(np.array(sensing_locs).T[1])
    for i in range(len(rate)):
        rate[i] = float(rate[i])
    value_list = [0,1,2,3,4]
    alloc_num = [0]*5
    for i in range(worker_num):
        result = number_of_certain_prob(value_list, rate)
        if result == 0:
            alloc_num[0] += 1
        elif result == 1:
            alloc_num[1] += 1
        elif result == 2:
            alloc_num[2] += 1
        elif result == 3:
            alloc_num[3] += 1
        elif result == 4:
            alloc_num[4] += 1
    for i in range(len(sensing_locs)):
        sensing_locs[i][1] = alloc_num[i]
    return sensing_locs

def generate_gps(loc, lat_step, lon_step):
    lat = loc[0] + random.uniform(-1, 1)*lat_step
    lon = loc[1] + random.uniform(-1, 1)*lon_step
    return tuple((lat,lon))

def worker_gps_sim(loc_gps, sens_locs, lat_step, lon_step):
    w_gps = []
    for loc in sens_locs:
        for w in range(loc[1]):
            w_gps.append(generate_gps(loc_gps[int(loc[0])], lat_step, lon_step))
    
    return w_gps

def dist_w_l(w_gps, sens_locs):
    MAX_INT = sys.maxsize
    w2l_dist = {}
    l2w_dist = {}
    for i in range(len(w_gps)):
        w2l_dist[i] = []
        for l in sens_locs:
            w2l_dist[i].append(geodesic(w_gps[i], l).meters)

    for j in range(len(sens_locs)):
        l2w_dist[j] = []
        for w in w_gps:
            l2w_dist[j].append(geodesic(sens_locs[j], w).meters)

    return w2l_dist, l2w_dist

def dist_info(bigram,unigram):
    sens_locs = zip_sensing_locs(bigram)
    benifit = []
    for item in sens_locs:
        benifit.append(item[1]*100)
    sens_locs = workers_assign2loc(sens_locs,1)

    lat_step = (42.302192553508-41.4459657) / 952 * 1
    lon_step = (12.9634722613942-11.7531545505395) / 1012 * 1

    loc_gps = []
    with open("./place/1min_100m1.csv", "r") as f:
        reader = csv.reader(f)
        for item in reader:
            loc_gps.append((float(item[0]), float(item[1])))

    w_gps = worker_gps_sim(loc_gps, sens_locs, lat_step, lon_step)

    s_locs = []
    for l in sens_locs:
        s_locs.append(loc_gps[int(l[0])])

    w2l_dist, l2w_dist = dist_w_l(w_gps, s_locs)

    o_l_dist = []
    for l in sens_locs:
        o_l_dist.append(geodesic(loc_gps[int(l[0])], loc_gps[unigram]).meters)
    for i in range(len(o_l_dist)):
        if o_l_dist[i] == 0:
            o_l_dist[i] = 120

    return o_l_dist,w2l_dist,benifit


def bipartite_graph(o_l_dist, w2l_dist,filename):
    MAX_INT = sys.maxsize
    for i in range(len(w2l_dist)):
        for j in range(len(o_l_dist)):
            if w2l_dist[i][j] > o_l_dist[j]:
                w2l_dist[i][j] = MAX_INT
    with open('./testcase/t5/'+filename+'.csv', 'a+') as csvfile:
                spamwriter = csv.writer(csvfile)
                spamwriter.writerow(w2l_dist[0])
    return w2l_dist
    

if __name__ == '__main__':
    test_obj = [("5583_5583", 5583), ('128_128', 128), ('4072_4072', 4072), ("15_15", 15), ("5501_4212",4212), 
                ("17_680", 680), ("940_940", 940), ("1779_1779", 1779), ("1051_1051" ,1051), ("5808_654" ,654)]
    for test_case in test_obj:
        #for i in range(99):
            o_l_dist,w2l_dist,benifit = dist_info(test_case[0],test_case[1])
            #bipartite_graph(o_l_dist, w2l_dist,test_case[0])
            with open('./testcase/t5/'+test_case[0]+'.csv', 'a+') as csvfile:
                spamwriter = csv.writer(csvfile)
                spamwriter.writerow(benifit)
    
    pass

